﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CPS1
{
    // główna klasa sygnału
    abstract public class Signal
    {
        public Boolean periodical; // czy sygnał jest okresowy ?
        public Boolean discrete; // czy sygnał jest dyskretny ? 
        public String name; // nazwa sygnału
        public Double A; // amplituda
        public Double T; // okres sygnału (potrzebny wszędzie by nie było problemów z typem Signal
        public Double t1; // czas początkowy
        public Double d; // czas trwania sygnału
        public Double f; // częstotliwość próbkowania

        public Double[,] calculatedValues; // obliczone wartości amplitud sygnału w danych czasach

        // wartość sygnału w danym czasie
        abstract public Double value(Double t);

        // funkcja obliczająca długość sygnału (jako ilość próbek)
        private int calculateSignalLength(Double[,] t)
        {
            // gdy sygnał jest okresowy, ogranicz jego długość do pełnych okresów
            if (this.periodical)
            {
                Double lengthOfSignal = this.d;
                Double tempLength = 0;

                // dodajemy kolejne okresy aż nie przekroczymy wartości długości sygnału
                do
                {
                    tempLength = tempLength + this.T;
                }
                while (tempLength <= lengthOfSignal);

                // gdy przekroczyliśmy wartość długości sygnału odejmujemy jeden okres
                if (tempLength > lengthOfSignal)
                {
                    tempLength -= this.T;
                }

                lengthOfSignal = tempLength;
                // obliczamy ilość próbek - czas * częstotliwość próbkowania
                lengthOfSignal = lengthOfSignal * this.f;
                return (int) Math.Ceiling(lengthOfSignal);
            }
            else // inaczej zwróć długość całego sygnału 
            {
                return t.Length / 2;
            }
        }

        // wartość średnia sygnału
        public Double meanValue(Double[,] t)
		{
			Double wyn;
			Double sum = 0.0;
            int lengthOfSignal = this.calculateSignalLength(t); 
            // sumujemy w pętli
            for (int i = 0; i < lengthOfSignal; i++)
            {
                sum += t[i, 1];
            }

            wyn = sum / (Math.Ceiling(t[lengthOfSignal - 1, 0] * this.f) - Math.Ceiling((t[0, 0]) * this.f) + 1);
			
			return wyn;
		}

        // wartość średnia bezwzględna sygnału
        public Double absMeanValue(Double[,] t)
		{
			Double wyn;
			Double sum = 0.0;
            int lengthOfSignal = this.calculateSignalLength(t); 
			// sumujemy w pętli
			for (int i = 0; i < lengthOfSignal; i++)
			{
				sum += Math.Abs(t[i,1]);	
			}

            wyn = sum / (Math.Ceiling(t[lengthOfSignal - 1, 0] * this.f) - Math.Ceiling((t[0, 0]) * this.f) + 1);
			
			return wyn;
		}

        // moc średnia sygnału
        public Double powerMean(Double[,] t)
		{
			Double wyn;
			Double sum = 0.0;
            int lengthOfSignal = this.calculateSignalLength(t);
			// sumujemy w pętli
			for (int i = 0; i < lengthOfSignal; i++)
			{
				sum += Math.Pow(t[i,1], 2);	
			}

            wyn = sum / (Math.Ceiling(t[lengthOfSignal - 1, 0] * this.f) - Math.Ceiling((t[0, 0]) * this.f) + 1);
			
			return wyn;
		}

        // wariancja sygnału w przedziale wokół wartości średniej
		// przekazujemy do funkcji rownież meanValue - mv
        public Double variance(Double[,] t, Double mv)
		{
			Double wyn;
			Double sum = 0.0;
            int lengthOfSignal = this.calculateSignalLength(t);
			// sumujemy w pętli
			for (int i = 0; i < lengthOfSignal; i++)
			{
				sum += Math.Pow(t[i,1] - mv, 2);	
			}

            wyn = sum / (Math.Ceiling(t[lengthOfSignal - 1, 0] * this.f) - Math.Ceiling((t[0, 0]) * this.f) + 1);
			
			return wyn;
		}

        // wartość skuteczna
        public Double effectiveValue(Double[,] t)
		{
			Double wyn;
			Double sum = 0.0;
            int lengthOfSignal = this.calculateSignalLength(t);
			// sumujemy w pętli
			for (int i = 0; i < lengthOfSignal; i++)
			{
				sum += Math.Pow(t[i,1], 2);	
			}
			
            wyn = sum / (Math.Ceiling(t[lengthOfSignal - 1, 0] * this.f) - Math.Ceiling((t[0, 0]) * this.f) + 1);
			wyn = Math.Sqrt(wyn);
			
			return wyn;
		}
        // funkcja obliczająca wartość sygnału
        public void calculateSignal()
        {
            int j = 0;
            Double i = this.t1;
            while (i < this.t1 + this.d && j < this.calculatedValues.Length / 2)
            {
                this.calculatedValues[j, 0] = i; // czas
                this.calculatedValues[j, 1] = this.value(i); // wartość
                j++;
                i = Math.Round(i + ((double)1.0 / (double)this.f), 6); // zwiększamy wartość czasu o czas próbkowania 
            }
        }
        // funkcja kopiująca sygnały
        public abstract Signal copy();
    }
}
